


//NetworkManager - to be Singleton??



#import "NetworkManager.h"
#import "GamePlay.h"

@interface NetworkManager()

@property(nonatomic) NSString *startLookingForOpponent;
@property(nonatomic) int playerNumber;
@property(nonatomic) int playerlastUpdate;
@property(nonatomic) int peerlastUpdate;

@property(nonatomic) GamePlay *gamePlay;

@end


@implementation NetworkManager

static BOOL isInited;

//@synthesize gameLoopTimer;
@synthesize gkPeerID;

//#ifdef kIsOS7OrLater
//
//#else
@synthesize gkSession;
//#endif

enum {
    gkMessageStartingSessionDate,
    gkMessageRandomGeneratedNumber,
    gkMessageCharacterAndLevelToPlay,
    gkMessageReadyToStart,
    gkMessagePositionOfEnemy
};


#pragma mark - init a Singleton object
+ (id)sharedInstance
{
    static NetworkManager *instance = nil;
    if ( !instance ) {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[super alloc] init];
        });
    }
    return instance;
}

+ (id)alloc
{
    return [NetworkManager sharedInstance];
}

- (id)init
{
    if ( !isInited ){
        self = [super init];
        if ( self ) {
            // self.gamePlay.gameState = kGameStateLaunchedMultiPlayer;
            //[self startLookingForOponent];
            
            self.gamePlay = [GamePlay sharedInstance];
        }
    }
	return self;
}

#pragma mark - Network
//#ifdef kIsOS7OrLater
//
//#else
- (void)startLookingForOponent
{
    if ( self.gamePlay.gameState == kGameStateLaunchedMultiPlayer ) {
        
        self.gamePlay.gameState = kGameStateLookingForOpponent;
        
        self.startLookingForOpponent = [NSDateFormatter localizedStringFromDate:[NSDate date] dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterFullStyle];
        
        NSLog(@"self.startLookingForOpponent = %@", self.startLookingForOpponent);
        
        //#ifdef kIsOS7OrLater
        //
        //#else
        GKPeerPickerController *picker;
        picker = [[GKPeerPickerController alloc] init];
        picker.delegate = self;
        
        [picker show];
        //#endif
    }
}

//cancel searching for an opponent
- (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
{
    
	picker.delegate = nil;
    self.gamePlay.gameState = kGameStateLaunchedMultiPlayer;
    
    //posting a notification
    [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNameForCanceledLookingForAnOpponent object:nil];
    
    NSLog(@"looking for opponent - cancel");

}

//connect with an opponent
- (void)peerPickerController:(GKPeerPickerController *)picker
              didConnectPeer:(NSString *)peerID toSession:(GKSession *)session
{
    self.gkPeerID = peerID;
    self.gkSession = session;
    [gkSession setDataReceiveHandler:self withContext:NULL];
    gkSession.delegate = self;
	
    [picker dismiss];
    picker.delegate = nil;
    
    //posting a notification
    [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNameForConnectedPeer object:nil];
    
    NSLog(@"connect to peerID = %@", peerID);
    
    [self sendingStartingTimeToFindWhoIsFirst];
}

//receive data
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer
          inSession:(GKSession *)session context:(void *)context {
    
    const char *incomingPacket = (const char *)[data bytes];
    char messageType = incomingPacket[0];
    NSLog(@"receive some data");

    
    switch (messageType) {
        case gkMessageStartingSessionDate:
        {
            NSData *receivedDataString = [data subdataWithRange:NSMakeRange(1, [data length]-1) ];
            NSString *opponentStartingDate = [[NSString alloc] initWithData:receivedDataString encoding:NSUTF8StringEncoding];
            NSLog(@"opponentStartingDate = %@",opponentStartingDate);
            
            [self checkWhoIsFirstBasedOnReceivedDate:opponentStartingDate];
            break;
        }
        case gkMessageRandomGeneratedNumber:
        {
            int peerGeneratedNumber = *(int *)(incomingPacket + 1);
            NSLog(@"gkMessageRandomGeneratedNumber");
            [self checkWhoIsFirstBasedOnReceivedNumber:peerGeneratedNumber];
            break;
        }
        case gkMessageCharacterAndLevelToPlay:
        {
            int currentLevel = *(int *)(incomingPacket + 1);
            int currentCharacter = *(int *)(incomingPacket + 2);
            
            //TODO
            //sending currentLevel and currentCharacter to GameScene
            self.gamePlay.characterType = currentCharacter;
            self.gamePlay.level = currentLevel;
            
            [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNamePlayerIsReadyToStart object:nil];
            
             NSLog(@"currentLevel = %d, currentCharacter =%d", currentLevel, currentCharacter);
            break;
        }
        case gkMessageReadyToStart:
        {

            //TODO
            //sending currentLevel and currentCharacter to GameScene
            [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNameOpponentIsReadyToStart object:nil];
            
            NSLog(@"Ready to start");
            break;
        }
            
        case gkMessagePositionOfEnemy:
        {
            int currentUpdate = *(int *)(incomingPacket + 1);
            
            if ( currentUpdate <= self.peerlastUpdate ) {
                return;
            }
            self.peerlastUpdate = currentUpdate;
            
            //TODO
            //sending opponent's position to GameScene - send Notification with new position
            
            
            NSLog(@"New enemy position,self.peerlastUpdate = %d", self.peerlastUpdate);
            break;
        }
    }
}

//// invalidate session
////
//- (void)invalidateSession:(GKSession *)session {
//	if(session != nil) {
//		[session disconnectFromAllPeers];
//		session.available = NO;
//		[session setDataReceiveHandler: nil withContext: NULL];
//		session.delegate = nil;
//	}
//}
//change in state
- (void)session:(GKSession *)session peer:(NSString *)peerID
 didChangeState:(GKPeerConnectionState)state {
    
    if ( [gkPeerID isEqualToString:peerID] && state == GKPeerStateDisconnected ) {
        
        [gkSession disconnectFromAllPeers];
        gkSession.delegate = nil;
        self.gkSession = nil;
        self.gkPeerID = nil;
        NSLog(@"disconnected");
        //posting a notification
        [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNameForDisconnectedOpponent object:nil];
    }
    //case GKPeerStateAvailable, GKPeerStateUnavailable, and GKPeerStateConnected
}

#pragma mark - set who plays first
- (void)sendingStartingTimeToFindWhoIsFirst
{
    self.gamePlay.gameState = kGameStateLookingWhoIsFirst;
    
    NSData* dataString = [self.startLookingForOpponent dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger lenDataString = [dataString length];
    
    NSMutableData *data = [NSMutableData dataWithCapacity:1+lenDataString];
    
    char messageType = gkMessageStartingSessionDate;
    [data appendBytes:&messageType length:1];
    [data appendData:dataString];
    
    
    NSLog(@"sendingStartingTimeToFindWhoIsFirst: sending data = %@",data);
    [gkSession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil];
}

- (void)sendingRandomGeneratedNumberToFindWhoIsFirst
{
    NSMutableData *data = [NSMutableData dataWithCapacity:1+sizeof(int)];
    char messageType = gkMessageRandomGeneratedNumber;
    [data appendBytes:&messageType length:1];
    self.playerNumber = rand();
    [data appendBytes:self.playerNumber length:sizeof(int)];
    
    NSLog(@"sendingRandomGeneratedNumberToFindWhoIsFirst: sending data = %@",data);
    [gkSession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil];
}

- (void)checkWhoIsFirstBasedOnReceivedDate:(NSString *)date
{
    NSDateFormatter *dateFormater = [[NSDateFormatter alloc] init];
    [dateFormater setDateStyle:NSDateFormatterShortStyle];
    [dateFormater setTimeStyle:NSDateFormatterFullStyle];
    
    NSDate *startedDateOpponent = [dateFormater dateFromString:date];
    NSDate *startedDatePlayer = [dateFormater dateFromString:self.startLookingForOpponent];
    NSLog(@"startedDatePlayer = %@, startedDateOpponent = %@", startedDatePlayer,startedDateOpponent);
    
    switch ([startedDatePlayer compare:startedDateOpponent])
    {
        case NSOrderedAscending:
            NSLog(@"startedDatePlayer");
            // startedDatePlayer is earlier in time than startedDateOpponent
            self.gamePlay.gameState = kGameStatePlayerChoosingLevelAndCharacter;
            //posting a notification
            [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNamePlayerChoosingCharacter object:nil];
            
            break;
            
        case NSOrderedSame:
            NSLog(@"Equal");
            // The dates are the same
            [self sendingRandomGeneratedNumberToFindWhoIsFirst];
            
            return;
        case NSOrderedDescending:
            // startedDatePlayer is later in time than startedDateOpponent
            NSLog(@"startedDateOpponent");
            self.gamePlay.gameState = kGameStatePlayerWaitsForLevelAndCharacter;
            
            //posting a notification
            [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNamePlayerWaitingForEnemyForChoosingCharacter object:nil];
            
            break;
    }
}

- (void)checkWhoIsFirstBasedOnReceivedNumber:(int)opponentNumber
{
    NSLog(@"self.playerNumber =%d, opponentNumber = %d", self.playerNumber,opponentNumber);
    
    if ( self.playerNumber == opponentNumber ) {
        NSLog(@"Equal");
        [self sendingRandomGeneratedNumberToFindWhoIsFirst];
        return;
    }
    else if ( self.playerNumber > opponentNumber ) {
        NSLog(@"self.playerNumber > opponentNumber");
        self.gamePlay.gameState = kGameStatePlayerChoosingLevelAndCharacter;
        //posting a notification
        [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNamePlayerChoosingCharacter object:nil];
    }
    else {
        NSLog(@"self.playerNumber < opponentNumber");
        self.gamePlay.gameState = kGameStatePlayerWaitsForLevelAndCharacter;
        //posting a notification
        [[NSNotificationCenter defaultCenter] postNotificationName:kNetworkNotificationNamePlayerWaitingForEnemyForChoosingCharacter object:nil];
    }
}

#pragma mark - sending data - enemyInfo and Level&Character
- (void)sendEnemyInformation:(EnemyInfo)enemyInfo
{
    //NSMutableData *data = [NSMutableData dataWithCapacity:1+sizeof(int)+sizeof(enemyInfo)];
    NSMutableData *data = [NSMutableData dataWithCapacity:1+sizeof(int)];
    char messageType = gkMessagePositionOfEnemy;
    [data appendBytes:&messageType length:1];
    self.playerlastUpdate++;
    [data appendBytes:self.playerlastUpdate length:sizeof(int)];
    
    //preparing data for enemyInfo
    NSLog(@"sendEnemyInformation: sending data = %@",data);
    [gkSession sendDataToAllPeers:data withDataMode:GKSendDataUnreliable error:nil];
}

- (void)sendToOpponentLevel:(int)level
               andCharacterType:(MessengerSpriteType)gameType
{
    NSMutableData *data = [NSMutableData dataWithCapacity:3];
    char messageType = gkMessageCharacterAndLevelToPlay;
    [data appendBytes:&messageType length:1];
    [data appendBytes:&level length:1];
    [data appendBytes:&gameType length:1];
    NSLog(@"Sending level and character - data=%@", data);
    
    [gkSession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil];
}


- (void)sendThatThePlayerIsReadyToPlay
{
    NSMutableData *data = [NSMutableData dataWithCapacity:1];
    char messageType = gkMessageReadyToStart;
    [data appendBytes:&messageType length:1];

    NSLog(@"player is ready to play =%@", data);
    
    [gkSession sendDataToAllPeers:data withDataMode:GKSendDataReliable error:nil];
}

//TODO - method for ending the connection

//#endif


@end
